<template>
    <!-- 使用淡入淡出过渡效果 -->
    <transition name="fade">
        <!-- 当 isVisible 为 true 时显示右键菜单，通过 style 动态设置菜单位置 -->
        <div v-if="isVisible" class="custom-context-menu" :style="{ left: `${x}px`, top: `${y}px` }" @click.self="hideMenu">
            <ul>
                <!-- 遍历菜单项数组，渲染每个菜单项 -->
                <li v-for="(item, index) in props.menuItems" :key="index" @click="handleMenuItemClick(item)">
                    <span class="menu-item-label">{{ item.label }}</span>
                </li>
            </ul>
        </div>
    </transition>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';

/**
 * 定义组件的 props
 * @property menuItems - 菜单项数组，每个菜单项包含标签和点击动作
 */
const props = defineProps<{
    menuItems: { label: string; action: () => void }[];
}>();

// 控制菜单是否显示的响应式变量
const isVisible = ref(false);
// 菜单显示位置的 x 坐标
const x = ref(0);
// 菜单显示位置的 y 坐标
const y = ref(0);

/**
 * 显示右键菜单的方法
 * @param event - 鼠标事件对象，用于获取鼠标点击位置
 */
const showMenu = (event: MouseEvent) => {
    const windowWidth = window.innerWidth;
    const windowHeight = window.innerHeight;
    const menuElement = document.querySelector('.custom-context-menu') as HTMLElement;
    // 动态获取菜单的实际宽度和高度
    const menuWidth = menuElement ? menuElement.offsetWidth : 100;
    const menuHeight = menuElement ? menuElement.offsetHeight : 100;

    // 计算菜单的 x 坐标
    x.value = event.clientX + menuWidth > windowWidth ? event.clientX - menuWidth : event.clientX;

    // 计算菜单的 y 坐标
    y.value = event.clientY + menuHeight > windowHeight ? event.clientY - menuHeight : event.clientY;

    isVisible.value = true;
    nextTick();

    // 重新获取菜单实际尺寸，确保计算准确
    const actualMenuWidth = menuElement ? menuElement.offsetWidth : 100;
    const actualMenuHeight = menuElement ? menuElement.offsetHeight : 100;

    // 再次检查并调整位置，确保顶点在鼠标位置
    if (x.value + actualMenuWidth > windowWidth) {
        x.value = event.clientX - actualMenuWidth;
    }
    if (y.value + actualMenuHeight > windowHeight) {
        y.value = event.clientY - actualMenuHeight;
    }
};

/**
 * 隐藏右键菜单的方法
 */
const hideMenu = () => {
    isVisible.value = false;
};

/**
 * 处理菜单项点击事件的方法
 * @param item - 点击的菜单项，包含标签和点击动作
 */
const handleMenuItemClick = (item: { label: string; action: () => void }) => {
    item.action();
    hideMenu();
};

/**
 * 处理文档点击事件，点击菜单外部区域时隐藏菜单
 * @param event - 鼠标事件对象
 */
const handleDocumentClick = (event: MouseEvent) => {
    if (isVisible.value) {
        const menuElement = document.querySelector('.custom-context-menu');
        if (menuElement && !menuElement.contains(event.target as Node)) {
            hideMenu();
        }
    }
};

// 组件挂载时添加文档点击事件监听器
onMounted(() => {
    document.addEventListener('click', handleDocumentClick);
});

// 组件卸载时移除文档点击事件监听器
onUnmounted(() => {
    document.removeEventListener('click', handleDocumentClick);
});

// 暴露 showMenu 方法，供父组件调用
defineExpose({
    showMenu,
});
</script>

<style scoped>
/* 右键菜单容器样式 */
.custom-context-menu {
    position: fixed; /* 固定定位 */
    background-color: var(--custom-bg-color); /* 使用定义的背景颜色 */
    border: 1px solid var(--custom-border-color); /* 使用定义的边框颜色 */
    border-radius: var(--custom-border-radius-base); /* 使用定义的圆角半径 */
    box-shadow: var(--custom-box-shadow); /* 使用定义的阴影效果 */
    z-index: 1000; /* 设置层级 */
    min-width: 120px; /* 最小宽度 */
    overflow: hidden; /* 防止内容溢出 */
}

/* 菜单列表样式 */
.custom-context-menu ul {
    list-style-type: none; /* 去除列表默认样式 */
    padding: 6px 0; /* 上下内边距 */
    margin: 0; /* 去除外边距 */
}

/* 菜单项样式 */
.custom-context-menu li {
    padding: 8px 20px; /* 内边距 */
    cursor: pointer; /* 鼠标悬停显示手型 */
    transition: background-color 0.2s ease, color 0.2s ease; /* 背景颜色和文字颜色过渡效果 */
    display: flex; /* 弹性布局 */
    align-items: center; /* 垂直居中对齐 */
    color: var(--custom-text-color-primary); /* 使用定义的主文字颜色 */
    font-size: 14px; /* 字体大小 */
}

/* 菜单项悬停样式 */
.custom-context-menu li:hover {
    background-color: var(--custom-fill-color-light); /* 使用定义的悬停背景颜色 */
    color: var(--custom-text-color-regular); /* 使用定义的次文字颜色 */
}

/* 菜单项标签样式 */
.menu-item-label {
    flex-grow: 1; /* 自动填充剩余空间 */
}

/* 淡入过渡激活状态样式 */
.fade-enter-active,
/* 淡出过渡激活状态样式 */
.fade-leave-active {
    transition: opacity 0.3s ease, transform 0.3s ease; /* 透明度和位移过渡效果 */
}

/* 淡入初始状态样式 */
.fade-enter-from,
/* 淡出结束状态样式 */
.fade-leave-to {
    opacity: 0; /* 透明度为 0 */
    transform: translateY(-10px); /* 向上偏移 10px */
}
</style>
